﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.Linq;
using System.Reflection;

namespace D.UtilEventbus
{
    /// <summary>
    /// 事件总线
    /// 发布-订阅模式的一种实现，是一种集中式事件处理机制，允许不同的组件之间进行彼此通信而又不需要相互依赖，达到一种解耦的目的
    /// 维护一个事件类型的字典，发布者、订阅者在事件总线中获取此字典并执行发布、订阅操作（维护一个事件源与事件处理的映射字典）
    /// 过单例模式，确保事件总线的唯一入口
    /// 同步执行，事件发送方在发出事件之后，会等待所有的事件消费方执行完毕后，才会回来继续执行自己后面的代码
    /// 事件发送方和事件消费方会在同一个线程中执行，消费方的执行线程取决于发送方
    /// 同一个事件的多个订阅者，在接收到事件的顺序上面有不同。谁先注册到EventBus的，谁先执行，如果是在同一个类中的两个订阅者一起被注册到EventBus的情况，收到事件的顺序跟方法名有关
    /// </summary>
    public class EventBus : IEventBus
    {
        /// <summary>
        /// 定义线程安全集合
        /// key:事件源
        /// value：事件处理
        /// </summary>
        private readonly ConcurrentDictionary<Type, List<Type>> eventAndHandlerMapping;

        public EventBus()
        {
            eventAndHandlerMapping = new ConcurrentDictionary<Type, List<Type>>();
            // 通过反射，将事件源与事件处理绑定
            MapEventToHandler();
        }

        #region 初始化

        private static EventBus _instance;
        protected static readonly object locker = new object();

        public static EventBus Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (locker)
                    {
                        // 如果类的实例不存在则创建，否则直接返回
                        if (_instance == null)
                        {
                            _instance = new EventBus();
                        }
                    }
                }
                return _instance;
            }
        }
        #endregion

        /// <summary>
        /// 根据事件源触发绑定的事件处理
        /// </summary>
        /// <typeparam name="TEventData"></typeparam>
        /// <param name="eventData"></param>
        public void Publish<TEventData>(TEventData eventData) where TEventData : IEventData
        {
            List<Type> handlers = eventAndHandlerMapping[eventData.GetType()];
            if (handlers != null && handlers.Count > 0)
            {
                foreach (var handler in handlers)
                {
                    MethodInfo methodInfo = handler.GetMethod("Handle");
                    if (methodInfo != null)
                    {
                        object obj = Activator.CreateInstance(handler);
                        methodInfo.Invoke(obj, new object[] { eventData });
                    }
                }
            }
        }

        /// <summary>
        /// 手动绑定事件源与事件处理
        /// </summary>
        /// <typeparam name="TEventData"></typeparam>
        /// <param name="eventHandler"></param>
        public void Subscribe<TEventData>(Type eventHandler)
        {
            List<Type> handlerTypes = eventAndHandlerMapping[typeof(TEventData)];
            if (!handlerTypes.Contains(eventHandler))
            {
                handlerTypes.Add(eventHandler);
                eventAndHandlerMapping[typeof(TEventData)] = handlerTypes;
            }
        }

        /// <summary>
        /// 手动解除事件源与事件处理的绑定
        /// </summary>
        /// <typeparam name="TEventData"></typeparam>
        /// <param name="eventHandler"></param>
        public void UnSubscribe<TEventData>(Type eventHandler)
        {
            List<Type> handlerTypes = eventAndHandlerMapping[typeof(TEventData)];
            if (handlerTypes.Contains(eventHandler))
            {
                handlerTypes.Remove(eventHandler);
                eventAndHandlerMapping[typeof(TEventData)] = handlerTypes;
            }
        }


        /// <summary>
        ///通过反射，将事件源与事件处理绑定
        /// </summary>
        /// <summary>
        private void MapEventToHandler()
        {
            Assembly assembly = Assembly.GetEntryAssembly();
            foreach (var type in assembly.GetTypes())
            {
                if (typeof(IEventHandler).IsAssignableFrom(type))//判断当前类型是否实现了IEventHandler接口
                {
                    Type handlerInterface = type.GetInterface("IEventHandler`1");//获取该类实现的泛型接口
                    if (handlerInterface != null)
                    {
                        Type eventDataType = handlerInterface.GetGenericArguments()[0]; // 获取泛型接口指定的参数类型
                        if (eventAndHandlerMapping.ContainsKey(eventDataType))
                        {
                            List<Type> handlerTypes = eventAndHandlerMapping[eventDataType];
                            handlerTypes.Add(type);
                            eventAndHandlerMapping[eventDataType] = handlerTypes;
                        }
                        else
                        {
                            var handlerTypes = new List<Type> { type };
                            eventAndHandlerMapping[eventDataType] = handlerTypes;
                        }
                    }
                }
            }
        }

        ///// <summary>
        ///// 事件订阅
        ///// </summary>
        ///// <typeparam name="T">订阅的时候，就应该知道订阅什么事件</typeparam>
        ///// <param name="eventHandler"></param>
        //public void Subscribe<T>(Action<object, IEventHandler> eventHandler) where T : IEvent
        //{
        //    lock (locker)
        //    {
        //        // 如果该事件类型存在
        //        if (eventAndHandlerMapping.ContainsKey(typeof(T)))
        //        {
        //            eventAndHandlerMapping[typeof(T)].Add(eventHandler);
        //        }
        //        else
        //        {
        //            eventAndHandlerMapping.AddOrUpdate(typeof(T), new List<Action<object, IEventHandler>>() { eventHandler });
        //        }

        //        var handlerTypes = eventAndHandlerMapping[typeof(TEventData)];
        //        if (!handlerTypes.Contains(eventHandler))
        //        {
        //            handlerTypes.Add(eventHandler);
        //            eventAndHandlerMapping[typeof(TEventData)] = handlerTypes;
        //        }
        //    }
        //}

        ///// <summary>
        ///// 解除订阅
        ///// </summary>
        ///// <typeparam name="T"></typeparam>
        ///// <param name="eventHandler"></param>
        //public void Unsubscribe<T>(Action<object, IEventHandler> eventHandler) where T : IEvent
        //{

        //}

    }
}
